package com.senseuni.da.ui

import android.animation.Animator
import android.animation.Animator.AnimatorListener
import android.animation.ObjectAnimator
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView.ScaleType
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import com.bumptech.glide.Glide
import com.elvishew.xlog.XLog
import com.jeremyliao.liveeventbus.LiveEventBus
import com.senseuni.da.DebugActivity
import com.senseuni.da.MainActivity
import com.senseuni.da.MyApplication
import com.senseuni.da.R
import com.senseuni.da.databinding.FragmentMainContentBinding
import com.senseuni.da.db.AppDatabase
import com.senseuni.da.db.dao.MediaDao
import com.senseuni.da.db.entity.MediaEntity
import com.senseuni.da.events.MyEvent
import com.senseuni.da.http.ApiDataSource
import com.senseuni.da.http.WeatherInfo
import com.senseuni.da.model.LogType
import com.senseuni.da.ui.dialog.*
import com.senseuni.da.utils.AppUtils
import com.senseuni.da.utils.MyCountDownTimer
import com.senseuni.da.utils.SpUtil
import com.senseuni.da.utils.showToast
import com.senseuni.da.worker.AppLog
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import java.lang.ref.WeakReference
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.roundToInt

class MainContentFragment : Fragment() {

    companion object {
        fun newInstance() = MainContentFragment()
        const val MSG_NEXT_IMAGE = 0x10
    }

    private lateinit var binding: FragmentMainContentBinding

    private var mActivity: MainActivity? = null

    private lateinit var viewModel: MainContentViewModel

    private lateinit var mDataSource: ApiDataSource

    private var mImageDuration = 30000L

    private var mCurrentIndex = 0

    private var mCurrentMediaId = 0L
    //当前播放的媒体类型
    private var mMimeType = "image"

    private var mScaleType:ScaleType = ScaleType.CENTER_CROP

    private var mMediaList: MutableList<MediaEntity>? = null

    private lateinit var mMediaDao: MediaDao

    private val dateFormat = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault())
    private val timeFormat = SimpleDateFormat("HH:mm", Locale.getDefault())

    private var mCountDownTimer: MyCountDownTimer? = null

    private lateinit var mHandler: UIHandler

    private class UIHandler(fragment: MainContentFragment) : Handler(Looper.getMainLooper()) {
        private val mOuter: WeakReference<MainContentFragment> = WeakReference(fragment)
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            val fragment = mOuter.get()
            when (msg.what) {
                MSG_NEXT_IMAGE -> {
                    fragment?.next()
                }
            }
        }
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mActivity = context as MainActivity?
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentMainContentBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        updateTime()

        binding.tvDate.setOnClickListener {
//            showNotification("提示", "新增图片一张")
        }

        binding.mnvGallery.setOnClickListener {
            getString(R.string.coming_soon).showToast()
        }

        binding.mnvFitFrame.setOnClickListener {
            if (mMediaList == null || mMediaList!!.size == 0) {
                XLog.e("no media data available")
                return@setOnClickListener
            }
            try {
                val media = mMediaList?.get(mCurrentIndex)
                if (media == null) {
                    XLog.e("media data is null")
                    return@setOnClickListener
                }
                if (media.mimeType == "video") {
                    XLog.e("video not supported")
                    getString(R.string.video_not_support_fit).showToast()
                    return@setOnClickListener
                }
                if (mScaleType == ScaleType.FIT_XY) {
                    mScaleType = ScaleType.FIT_CENTER
                } else {
                    mScaleType = ScaleType.FIT_XY
                }
                binding.imageView.scaleType = mScaleType
            } catch (e: Exception) {
                XLog.e("Fit to Frame error:${e.message}")
            }
        }

        binding.mnvReact.setOnClickListener {
            getString(R.string.coming_soon).showToast()
        }

        binding.mnvHidePhoto.setOnClickListener {
            onTouchClick()
            hideMedia(mCurrentMediaId)
            mCountDownTimer?.stop()
            if (mMediaList?.size == 0) {
                mActivity?.showDefault()
                return@setOnClickListener
            }
            next()
        }

        binding.mnvSetDuration.setOnClickListener {
            val dialog = DurationSettingDialog(context)
            dialog.setOnResultListener { _dialog, result ->
                _dialog.dismiss()
                mCountDownTimer?.stop()
                XLog.d("set duration:$result")
                mImageDuration = result * 1000
                handleNext()
            }
            dialog.create().show()
        }

        binding.llMainSetting.setOnClickListener {
            XLog.d("setting clicked")
            onTouchClick()
            val intent = Intent()
            intent.setClass(requireContext(), SettingActivity::class.java)
            startActivity(intent)
//            mActivity?.openSetting()
        }

        binding.root.setOnClickListener {
            onTouchClick()
        }

        binding.llMainSetting.setOnLongClickListener {
            val intent = Intent()
            intent.setClass(requireContext(), DebugActivity::class.java)
            startActivity(intent)
            return@setOnLongClickListener true
        }

        binding.ivMainPower.setOnClickListener {
            val dialog = PowerDialog(requireContext())
            dialog.setOnResultListener { _, result ->
                if (result == 0) {
                    AppUtils.shutdown()
                } else if (result == 1) {
                    AppUtils.reboot()
                } else {
                    AppUtils.screenOff()
                }
            }
            dialog.create().show()
        }
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        XLog.d("MainContentFragment onActivityCreated")
        viewModel = ViewModelProvider(this).get(MainContentViewModel::class.java)

        binding.playerView.player = ExoPlayer.Builder(requireContext()).build()
        binding.playerView.visibility = View.GONE
        binding.imageView.visibility = View.GONE

        val player = binding.playerView.player
        if (player == null) {
            XLog.e("Player is null")
            //一般不会走到这里
            AppLog.instance.log(LogType.ERROR, "Player is null!!!")
            return
        }

        player.addListener(object : Player.Listener{
            override fun onPlaybackStateChanged(playbackState: Int) {
                when (playbackState) {
                    Player.STATE_IDLE -> XLog.d("STATE_IDLE")
                    Player.STATE_BUFFERING -> XLog.d("STATE_BUFFERING")
                    Player.STATE_ENDED -> {
                        XLog.d("STATE_ENDED")
                        next()
                    }
                    Player.STATE_READY -> XLog.d("STATE_READY")
                    else -> XLog.d("playbackState:${playbackState}")
                }
            }

            override fun onPlayerError(error: PlaybackException) {
                val currentMedia = mMediaList?.get(mCurrentIndex)
                currentMedia?.let {
                    XLog.e("Media:${it.path} Play error:%s", error.message)
                    AppLog.instance.log(LogType.ERROR, "Media:${it.uuid} Play error:${error.message}")
//                    val currentPosition = binding.playerView.player?.currentPosition ?: 0
//                    onPlayError(it.taskId , it.materialId, currentPosition)
                    false
                }
                //播放失败，直接下一个
                next()
            }
        })
        player.repeatMode = Player.REPEAT_MODE_OFF
        player.playWhenReady = true
        binding.playerView.useController = false

        mImageDuration = SpUtil.getImageDuration() * 1000
        XLog.d("image duration:$mImageDuration")
//        mHandler = UIHandler(this)

        mDataSource = ApiDataSource.instance
        mMediaDao = AppDatabase.getInstance().mediaDao()

        mMediaList = mMediaDao.findAll() as MutableList<MediaEntity>
        mCurrentIndex = 0
        if (mMediaList == null) {
            mMediaList = mutableListOf()
        }
        XLog.d("MainContentFragment onActivityCreated.size=" + mMediaList?.size)
        mMediaList?.let {
            displayImage()
            if (it.size > 1) {
                handleNext()
            }
        }

        LiveEventBus.get<Long>(MyEvent.KEY_IMAGE_DELETE).observe(this) {
            XLog.d("image deleted:$it")
            mMediaList?.let { list ->
                //遍历list，如果找到id = it的数据，要移除
                list.forEachIndexed { index, entity ->
                    if (entity.id == it) {
                        list.removeAt(index)
                        if (mCurrentIndex == index) {
                            XLog.d("remove current play image, play next")
                            next()
                        }
                        return@observe
                    }
                }
            }
        }
    }

    private fun next() {
//        XLog.d("next>>>>$mImageDuration")
        if (isDetached) {
            return
        }
        mCurrentIndex++
        val count = mMediaList?.size ?: 0
        if (count == 0) {
            XLog.d("no more media to play")
            mActivity?.showDefault()
            return
        }

        if (mCurrentIndex == count) {
            mCurrentIndex = 0
        }
//        fadeOutAndIn()

        val media = mMediaList?.get(mCurrentIndex)
        media?.let {
            if (it.mimeType == "video") {
                playVideo()
//                XLog.d("not supported video")
//                next()
            } else {
                displayImage()
                if (count > 1) {
                    handleNext()
                }
            }
        }
    }

    private fun handleNext() {
//        XLog.d("MainContentFragment onActivityCreated start countdown:$mImageDuration")
        mCountDownTimer = object : MyCountDownTimer(mImageDuration, 1000L) {
            override fun onTimeTick(value: Long) {
            }
            override fun onTimeFinish() {
                XLog.d(">>image play end")
                next()
            }
        }
        mCountDownTimer!!.start()
    }

    private fun hideMedia(id: Long) {
        mMediaDao.updateHide(id)
        mMediaList?.forEach {
            if (it.id == id) {
                it.hide = true
                mMediaList?.remove(it)
                return
            }
        }
    }

//    private fun getNextMedia() : MediaEntity? {
//        mCurrentIndex ++;
//        val count = mMediaList?.size ?: 0
//        if (mCurrentIndex >= count) {
//            mCurrentIndex = 0
//        }
//        return
//    }

    private fun updateTime() {
        binding.tvTime.text = timeFormat.format(Date())
        binding.tvDate.text = dateFormat.format(Date())
        XLog.d("time:" + binding.tvTime.text)
    }

    fun addImage(media: MediaEntity) {
        XLog.d("addImage:%s", media.path)
        mMediaList?.add(media)
        if (mMediaList?.size == 1) {
            mCurrentIndex = 0;
            displayImage()
        }
    }

    fun addFirst(media: MediaEntity) {
        mMediaList?.add(0, media)
        XLog.d("addFirst:%s,,media.size:%d", media.path , mMediaList?.size)
        if (mMediaList?.size == 1) {
            mCurrentIndex = 0;
            if (media.mimeType == "video") {
                playVideo()
            } else {
                displayImage()
            }
        } else {
            mCountDownTimer?.stop()
            mCurrentIndex = 0
//            fadeOutAndIn()
            if (media.mimeType == "video") {
                playVideo()
            } else {
                displayImage()
                handleNext()
            }
        }
    }

    private fun displayImage(showAnim:Boolean = false) {
        binding.imageView.visibility = View.VISIBLE
        binding.playerView.visibility = View.GONE
        mMediaList?.let {
            if (mCurrentIndex >= it.size) {
                mCurrentIndex = 0
            }
            val path = it[mCurrentIndex].path
            mCurrentMediaId = it[mCurrentIndex].id
            mMimeType = "image"
            XLog.d("display:$path")
            Glide.with(requireContext())
                .load(path)
//                .centerCrop()
                .into(binding.imageView)
//            if (showAnim) {
//                binding.imageView.alpha = 0f
//                fadeIn()
//            }
        }
    }

    private fun playVideo() {
        binding.imageView.visibility = View.GONE
        binding.playerView.visibility = View.VISIBLE
        mMediaList?.let {
            if (mCurrentIndex >= it.size) {
                mCurrentIndex = 0
            }
            val media = it[mCurrentIndex]
            mCurrentMediaId = media.id
            mMimeType = "video"
            binding.playerView.player?.setMediaItem(MediaItem.fromUri("file://${media.path}"))
            binding.playerView.player?.prepare()
        }
    }

    private fun fadeIn() {
        val fadeIn = ObjectAnimator.ofFloat(binding.imageView, "alpha", 0f, 1f)
        fadeIn.duration = 1000
        fadeIn.start()
    }

    private fun fadeOutAndIn() {
        val animator = ObjectAnimator.ofFloat(binding.imageView, "alpha", 1f, 0f)
        animator.duration = 1000
        animator.addListener(object : AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
            }

            override fun onAnimationEnd(animation: Animator) {
                displayImage(true)
            }

            override fun onAnimationCancel(animation: Animator) {
            }

            override fun onAnimationRepeat(animation: Animator) {
            }
        })
        animator.start()
    }

    private fun onTouchClick() {
        if (binding.groupMenu.visibility == View.VISIBLE) {
            binding.groupMenu.visibility = View.GONE
        } else {
            binding.groupMenu.visibility = View.VISIBLE
        }
    }

    fun showTime() {
        updateTime()
    }

    fun showWeatherInfo(weatherInfo: WeatherInfo) {
        if (isDetached) {
            return
        }
        weatherInfo.main.temp?.let {
            binding.tvTemperature.text = "${it.roundToInt()}°"
        }
        weatherInfo.weather?.let {
            val icon = it[0].icon
            XLog.d("get weather icon:$icon")
            if (!icon.isNullOrEmpty()) {
                //http://openweathermap.org/img/w/"+obj.weather[0].icon+".png"
                val url = "http://openweathermap.org/img/w/$icon.png"
                XLog.d("get weather icon url:$url")
                binding.ivTemperatureIcon.let { iv ->
                    Glide.with(MyApplication.app.applicationContext)
                        .load(url)
                        .into(iv)
                }
            }
        }
    }

    private fun showAddFriendDialog() {
        val dialog = AddFriendDialog(context)
        dialog.setQRCode(SpUtil.getQRCode())
        dialog.create().show()
    }

    override fun onPause() {
        super.onPause()
        XLog.d("onPause:")
        if (mMimeType == "video") {
            binding.playerView.player?.pause()
        } else {
            mCountDownTimer?.pause()
        }
    }

    override fun onResume() {
        super.onResume()
        XLog.d("onResume:")
        if (mMimeType == "video") {
            binding.playerView.player?.play()
        } else {
            mCountDownTimer?.resume()
        }
    }

    fun onInitDone() {
        updateTime()
        getWeatherInfo()
    }

    private fun getWeatherInfo() {
        mDataSource.getWeatherInfo()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Observer<WeatherInfo> {
                override fun onSubscribe(d: Disposable) {
                }

                override fun onNext(t: WeatherInfo) {
                    XLog.d("get weather info success:" + t.main.temp)
                    if (!isDetached) {
                        showWeatherInfo(t)
                    }
                }

                override fun onError(e: Throwable) {
                    XLog.e("get weather info fail:" + e.message)
                }

                override fun onComplete() {
                }
            })
    }

    override fun onDestroy() {
        super.onDestroy()
        mCountDownTimer?.stop()
        binding.playerView.player?.release()
        binding.playerView.player = null
    }

}